﻿#include "pch.h"
#include <graphics.h>
#include <conio.h>
#include <cmath>
#include <ctime>
#include <iostream>
#include <string>
#include <tchar.h>
#include "tool.h"
using namespace std;

extern int direction;
const int radius = 3;//蛇部分半径
const int dia = radius * 2;//直径
const int mapX = dia * 40;
const int mapY = dia * 40;

void Init(Snake &snake, int &newx, int &newy) {
	/*初始化界面、画布、蛇坐标队列*/
	system("title SnakeGame");
	initgraph(mapX+150,mapY);
	CreateQueue(snake.Q);
	snake.score = 0;
	int head = dia*13 + radius;
	int tail = head - dia * 4;
	for (int i = 0; i < 5; ++i) {
		AddQ(snake.Q, { tail + dia * i,head });
	}
	newx = head + dia;
	newy = head;
}

void char2tchar(const char* _char, TCHAR* tchar) {
	/*char类型转tchar*/
	int iLength;
	iLength = MultiByteToWideChar(CP_ACP, 0, _char, strlen(_char) + 1, NULL, 0);
	MultiByteToWideChar(CP_ACP, 0, _char, strlen(_char) + 1, tchar, iLength);
}

void Show(Snake &snake,int &newx, int &newy, Point &food, int speed) {
	int head = snake.Q->Rear;
	int tail = (snake.Q->Front + 1) % snake.Q->QueueSize;
	//cleardevice();
	BeginBatchDraw();
	//绘制地图边界
	//设置黄色画笔、黑色背景
	setcolor(YELLOW);
	setfillcolor(BLACK);
	fillrectangle(0, 0, mapX, mapY); //地图范围

	//绘制蛇身
	for (int i = tail; i != head;i++){
		fillcircle(snake.Q->Data[i].x, snake.Q->Data[i].y, radius);
		if (i == snake.Q->QueueSize - 1) {
			i = -1;
		}
	}

	//绘制蛇头
	setcolor(YELLOW);
	setfillcolor(RED);
	fillcircle(snake.Q->Data[head].x, snake.Q->Data[head].y, radius);
		
	//绘制计分板
	outtextxy(mapX + 30, 30, _T("贪吃蛇"));
	outtextxy(mapX + 30, 50, _T("得分："));
	
	char buffer[10];
	TCHAR tchar[10];
	_itoa_s(snake.score, buffer, 10, 10);
	char2tchar(buffer,tchar);
	outtextxy(mapX + 70, 50, tchar);

	//生成下一位置的坐标
	Point point;
	point.x = newx;
	point.y = newy;

	//判断是否吃到食物
	if (GetFood(snake, food)) {
		CreateFood(snake, food);
		DrawFood(food);
		AddQ(snake.Q, point);
		snake.score++;
	}
	else {
		DrawFood(food);
		AddQ(snake.Q, point);
		DeleteQ(snake.Q);
	}
	
	//判断是否撞墙
	if (HitWall(snake)) {
		switch (direction) {
			case 0://left
				direction = 3;
				break;
			case 1://right
				direction = 2;
				break;
			case 2://up
				direction = 0;
				break;
			case 3://down
				direction = 1;
				break;
		}
	}
	//判断是否撞到自身
	if (HitSelf(snake)) {
		Sleep(1000);
		DrawGameover(snake);
		system("pause");
		closegraph();
	}
	
	
	FlushBatchDraw();
	Sleep(speed);
}

void UpdateWithInput(){
	//如果键盘有输入
	while (_kbhit())
	{
		char ch = _getch();
		fflush(stdin);
		switch (ch)
		{
		case 'A':
		case 'a':
			if (direction != 1) {
				direction = 0;//left
			}
			break;
		case 'D':
		case 'd':
			if (direction != 0) {
				direction = 1;//right
			}
			break;
		case 'W':
		case 'w':
			if (direction != 3) {
				direction = 2;//up
			}
			break;
		case 'S':
		case 's':
			if (direction != 2) {
				direction = 3;//down
			}
			break;
		}

	}
}

void UpdateWithoutInput(int &newx,int &newy){
	/*如果键盘没输入，根据方向生成下一步坐标*/
	if (direction == 0){
		newx -= dia;
	}

	if (direction == 1){
		newx += dia;
	}
	if (direction == 2) {
		newy -= dia;
	}
	if (direction == 3) {
		newy += dia;
	}
}

void CreateFood(const Snake snake, Point &food) {
	/*随机生成食物坐标*/
	int head = snake.Q->Rear;
	int tail = (snake.Q->Front + 1) % snake.Q->QueueSize;
	while (1) {
		srand((unsigned)time(NULL));
		int tmp_x = rand() * dia % mapX + radius;
		int tmp_y = rand() * dia % mapY + radius;
		bool flag = false;
		//遍历蛇身
		for (int i = tail; i != head; ++i) {
			if ((fabs(snake.Q->Data[i].x - tmp_x) < radius) && (fabs(snake.Q->Data[i].y - tmp_y) < radius)) {
				flag = true;
				break;
			}
			if (i == snake.Q->QueueSize) {
				i = -1;
			}
		}
		if (flag) continue;

		food.x = tmp_x;
		food.y = tmp_y;
		break;
	}
}

void DrawFood(const Point food) {
	/*绘制食物*/
	setcolor(YELLOW);
	setfillcolor(YELLOW);
	fillcircle(food.x, food.y, radius);
}

bool GetFood(Snake &snake, const Point food) {
	/*判断是否吃到食物*/
	int head = snake.Q->Rear;
	int diffx = abs(snake.Q->Data[head].x - food.x);
	int diffy = abs(snake.Q->Data[head].y - food.y);
	if (diffx < radius * 2 && diffy < radius * 2) {
		return true;
	}
	else
		return false;
}

bool HitWall(Snake &snake) {
	/*判断是否撞墙*/
	int head = snake.Q->Rear;
	Point next;
	next.x = snake.Q->Data[head].x;
	next.y = snake.Q->Data[head].y;
	switch (direction) {
	case 0: //left
		if (next.x == radius)
			return true;
		break;
	case 1: //right
		if (next.x == (mapX - radius))
			return true;
		break;
	case 2: //up
		if (next.y == radius)
			return true;
		break;
	case 3: //down
		if (next.y == (mapY - radius))
			return true;
		break;
	}
	return false;
}

bool HitSelf(Snake &snake) {
	/*判断是否撞到自身*/
	int head = snake.Q->Rear;
	int tail = (snake.Q->Front + 1) % snake.Q->QueueSize;

	for (int i = tail; i != head; ++i) {
		if (snake.Q->Data[i].x == snake.Q->Data[head].x && snake.Q->Data[i].y == snake.Q->Data[head].y) {
			return true;
		}
		if (i == snake.Q->QueueSize) {
			i = -1;
		}
	}
	return false;
}

int DrawMenu() {
	/*绘制开始菜单*/
	BeginBatchDraw();
	
	setcolor(YELLOW);
	setfillcolor(BLACK);
	fillrectangle(0, 0, mapX+150, mapY);

	char buffer[10];
	settextcolor(WHITE);
	outtextxy(mapX / 2 + 10, mapY / 2 - 70, _T("贪吃蛇"));
	outtextxy(mapX / 2 - 70, mapY / 2 - 30, _T("选择难度：1.简单"));
	outtextxy(mapX / 2 + 10, mapY / 2 - 10, _T("2.中等"));
	outtextxy(mapX / 2 + 10, mapY / 2 + 10, _T("3.困难"));
	
	FlushBatchDraw();
	
	char ch = _getch();
	switch (ch) {
	case '1':	return 200;
	case '2':	return 100;
	case '3':	return 50;
	}
	_kbhit();
}

void DrawGameover(Snake &snake) {
	/*绘制游戏结束菜单*/
	BeginBatchDraw();

	setcolor(YELLOW);
	setfillcolor(BLACK);
	fillrectangle(mapX/2, mapY/2, mapX/2+100, mapY/2+60);

	char buffer[10];
	TCHAR tchar[10];
	_itoa_s(snake.score, buffer, 10, 10);
	char2tchar(buffer, tchar);
	settextcolor(RED);
	outtextxy(mapX/2+10, mapY/2+10, _T("GAME OVER"));
	outtextxy(mapX/2+10, mapY/2+30, _T("最终得分："));
	outtextxy(mapX/2+80, mapY/2+30, tchar);
	FlushBatchDraw();
}